<?php
namespace app\admin\controller;
use app\admin\controller\Base;
use think\Db;
class Workflowajax extends Base
{
    public $now_user;
    /**
     * 
     * 详情页 details
     * 1,假设是当前用户，郝宇
     * 2，假设是上司，吴总监
     * 3，假设是总经理，廖总
     * @return array|void
     */
    public function _initialize()
    {
        $this->now_user = session('id');
//        $this->now_user = 1;  //全局配置替换登陆ID 只替换了ID，其他没有替换
    }
    /*********************************************************************模版生产**********************************************************************/
    /**
     * 获取审批流模板列表
     */
    public function get_flow_list()
    {
        $list = Db::name('wf_flow')->where(['isdelete'=>0])->field('id,name,total,state')->select();
        $lists = array();
        foreach ($list as $key => $val) {
            foreach ($val as $k => $v) {
                $lists[$key][$k] = $v;
            }
        }
        $data = array(
            'code' => '200',
            'msg' => '请求成功',
            'count' => count($lists),
            'data' => $lists,
        );
        return $data;
    }
    /**
     * 创建审批流模板  name|功能名（汉字） controller|控制器（代码）table_name|表名（代码）
     */
    public function add_flow()
    {
        if (request()->isAjax()) {
            $type=input('type');
            $param = request()->post();
            $where = $param;
            $where['is_form_extend'] = $type;
            $where['isdelete']=$param['isdelete'] = 0;
            $field = array();
            Db::startTrans();
            try{
                $res = Db::name('wf_flow')->insert($where);
                if($type == 1 && $res){
                    $flow_id = Db::name('wf_flow')->getLastInsID();
                    $table_names = array('sys_user');
                    array_push($table_names,$where['table_name']);
                    $fields = $this->get_fields($table_names,$flow_id);
                    $fs = Db::name('wf_form_field')->insertAll($fields);
                    if($fs){
                        $msg='添加成功';
                        $code = 200;
                    }else{
                        $msg='表单字段创建失败';
                        $code = -2;
                    }
                }elseif($type == 0 && $res){
                    $msg='添加成功';
                    $code = 200;
                }else{
                    $msg='添加失败';
                    $code = -1;
                }
                // 提交事务
                Db::commit();
            } catch (\Exception $e) {
//                 回滚事务
                $msg = '添加失败(完全回滚)';
                $code = -3;
                Db::rollback();
            }
            return json($msg, $code);
        }
    }
    /**
     * 创建审批流模板  name|功能名（汉字） controller|控制器（代码）table_name|表名（代码）
     */
    public function edit_flow()
    {
        if (request()->isAjax()) {
            $type=input('type');
            $param = request()->post();
            $flow_id = $param['id'];
            unset($param['id']);
            $field = array();
            Db::startTrans();
            try{
                $res = Db::name('wf_flow')->where(['id'=>$flow_id])->update($param);
                if($type == 1 && $res){
                    $this->match_updata($flow_id);
                    $msg='修改成功';
                    $code = 200;
                }elseif($type == 0 && $res){
                    $msg='添加成功';
                    $code = 200;
                }else{
                    $msg='添加失败';
                    $code = -1;
                }
                // 提交事务
                Db::commit();
            } catch (\Exception $e) {
//                 回滚事务
                $msg = '添加失败(完全回滚)';
                $code = -3;
                Db::rollback();
            }
            return json($msg, $code);
        }
    }
    /**
     * 增量修改字段
     * @param string $flow_id 模板ID
     */
    public function match_updata($flow_id){
        //获取已有信息--含绑定表名
        $flow = Db::name('wf_flow')->find($flow_id);
        //查询原始字段字段
        $original_list = Db::name('wf_form_field')->where(['flow_id'=>$flow_id])->select();
        //查询新的字段
        $table_names = array('sys_user');
        array_push($table_names,$flow['table_name']);
        $new_list = $this->get_fields($table_names,$flow_id);
        //不变的字段
        $unchanged = $this->get_field_un($original_list,$new_list);
        //新增字段
        $add = $this->get_field_action($new_list,$unchanged);
        //删除字段
        $del = $this->get_field_action($original_list,$unchanged); //需要删除ID
        if(!empty($del)){
            foreach($del as $k=>$v){
                Db::name('wf_form_field')->where(['id'=>$v['id']])->update(['isdelete'=>0]);
            }
        }
        if(!empty($add)){
            foreach($add as $k=>$v){
                $field_id = Db::name('wf_form_field')->where(['field_name'=>$v['field_name'],'source_table'=>$v['source_table'],'isdelete'=>1])->find()['id'];
                if($field_id){ //有历史文件修改状态
                    Db::name('wf_from_field')->where(['id'=>$field_id])->update(['isdelete'=>0]);
                }else{ //否则真的新增
                    Db::name('wf_from_field')->where(['id'=>$field_id])->insert($v);
                }
            }
        }
    }
    /**
     * 不变的字段
     * @param array $old 旧的所有字段
     * @param array $new 新的所有字段
     * @return array $unchanged 不变的字段
     */
    public function get_field_un($old,$new){
        $unchanged = array();
        foreach($old as $key=>$val){
            foreach($new as $k=>$v){
                if($v['field_name']==$val['field_name'] && $v['source_table']==$val['source_table']){
                    array_push($unchanged,$old[$key]);
                }
            }
        }
        return $unchanged;
    }
    /**
     * 获取需要新增的字段
     * @param array $array 需要对比的字段
     * @param array $un 参照字段
     * @return array $array 变动字段
     */
    public function demo($array,$un){
        foreach($array as $key=>$val){
            foreach ($un as $k=>$v){
                if($val['field_name'] == $v['field_name'] && $val['source_table'] == $v['source_table']){
                    unset($array[$key]);
                }
            }
        }
        return $array;
    }
    /**
     * 获取外接表单字段
     * @param array $table_name  表名数组
     * @param bool $flow_id   模板ID
     * @return mixed|string
     */
    public function get_fields($table_name,$flow_id)
    {
        $data = array();
        $num = 0;
        foreach($table_name as $key=>$val){
            $original = $this->get_db_column_comment($val);
            foreach($original as $k=>$v){
            if(empty($v['comment'])){
                $data[$num]['name']=$v['field'];
            }else{
                $data[$num]['name']=$v['comment'];  //字段注释名
            }
                $data[$num]['field_name'] = $v['field'];  //字段代码
                $data[$num]['source_table'] = $val;  //来源表单
                $data[$num]['field_type'] = 1;
                $data[$num]['flow_id'] = $flow_id;
                $data[$num]['isdelete'] = 0;
                $num++;
            }
        }
        return $data;
    }
    /**
     * 根据表名获取表字段和描述
     * @param string $table_name
     * @param bool $field
     * @param string $table_schema
     * @return mixed|string
     */
    function get_db_column_comment($table_name = '', $field = true, $table_schema = '')
    {
        // 接收参数
        $database = config('database');
        $table_schema = empty($table_schema) ? $database['database'] : $table_schema;
        $table_name = $database['prefix'] . $table_name;
        // 缓存名称
        $fieldName = $field === true ? 'allField' : $field;
        $cacheKeyName = 'db_' . $table_schema . '_' . $table_name . '_' . $fieldName;
        // 处理参数
        $param = [
            $table_name,
            $table_schema
        ];
        // 字段
        $columeName = '';
        if ($field !== true) {
            $param[] = $field;
            $columeName = "AND COLUMN_NAME = ?";
        }
        // 查询结果
        $result = Db:: query("SELECT COLUMN_NAME as field,column_comment as comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ? AND table_schema = ? $columeName", $param);
        if (empty($result) && $field !== true) {
            return $table_name . '表' . $field . '字段不存在';
        }
        $data = $result;
        return count($data) == 1 ? reset($data) : $data;
    }
    /**
     * 删除流程模板
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function delete_flow()
    {
        if (request()->isAjax()) {
            Db::startTrans();
            //要删除的节点ID
            $flow_id = input('id');
            $flow = Db::name('wf_flow')->find('$flow_id');
            $bool = "";
            try {
                //删除相关节点数据
                Db::name('wf_process')->where('flow_id', 'eq', $flow_id)->update(['isdelete' => 1]);
                //删除对应表单字段
                if($flow['is_form_extend']==1){
                    Db::name('wf_form_field')->where('form_extend_id', 'eq', $flow['form_extend_id'])->update(['isdelete' => 1]);
                }else{
                    Db::name('wf_form_field')->where('flow_id', 'eq', $flow_id)->update(['isdelete' => 1]);
                }
                //删除审批流模版
                Db::name('wf_flow')->where('id', 'eq', $flow_id)->update(['isdelete' => 1]);
                Db::commit();
                $bool = true;
            } catch (\Exception $e) {
                Db::rollback();
                $bool = false;
            }
            if ($bool) {
                return $this->success('删除成功');
            } else {
                return $this->error('删除失败');
            }
        }
    }
    /**
     * 删除审批流
     */
    public function delete_workflow()
    {
        if (request()->isAjax()) {
            Db::startTrans();
            //要删除的节点ID
            $workflow_id = input('id');
            $bool = "";
            try {
                //删除对应操作表
                Db::name('wf_examine')->where('workflow_id', 'eq', $workflow_id)->update(['isdelete' => 1]);
                //删除相关节点数据
                Db::name('wf_workprocess')->where('workflow_id', 'eq', $workflow_id)->update(['isdelete' => 1]);
                //删除审批流模版
                Db::name('wf_workflow')->where('id', 'eq', $workflow_id)->update(['isdelete' => 1]);
                Db::commit();
                $bool = true;
            } catch (\Exception $e) {
                Db::rollback();
                $bool = false;
            }
            if ($bool) {
                return $this->success('删除成功');
            } else {
                return $this->error('删除失败');
            }
        }
    }
    /**
     * 添加节点 paste
     */
    public function add_process()
    {
        if (request()->isAjax()) {
            $where = array();
            $input = input();
            if ($input['type'] == 'paste') {
                $process_id = isset($input['process_id']) ? $input['process_id'] : '';
                $attr = Db::name('wf_process')
                    ->field('flow_id,
                    process_name,
                    icon,
                    style,
                    auto_person,
                    auto_unlock,
                    auto_sponsor_uids,
                    auto_respon_uids,
                    auto_role_ids,
                    range_user_ids,
                    range_dept_ids,
                    range_role_ids,
                    con_sign,
                    con_sign_vsb,
                    con_sign_back,
                    write,
                    secret'
                    )
                    ->find($process_id); //复制节点通用属性
                //处理style中的坐标到刚刚粘贴的坐标
                $array = json_decode($attr['style'], true);
                $array['top'] = $input['top'];
                $array['left'] = $input['left'];
                $attr['style'] = json_encode($array);   //样式数据
                $res = Db::name('wf_process')->insert($attr);
                if ($res) {
                    return $this->success('创建成功', '', $res);
                }
            }
            $where['style'] = json_encode(array(
                "top" => isset($input['top']) ? $input['top'] : rand(10, 999) . 'px',
                "left" => isset($input['left']) ? $input['left'] : rand(10, 999) . 'px',
                "width" => "200px",
                "height" => "50px"
            ));
            $where['flow_id'] = input('flow_id');
            $where['isdelete'] = 0;
            //写入节点表
            $res = Db::name('wf_process')->insert($where);
            $newId = Db::name('wf_process')->getLastInsID();
            //回写审核节点数量
            Db::name('wf_flow')->where('id', input("flow_id"))->update(['total' => (count(Db::name('wf_process')->where('flow_id', $where['flow_id'])->select()) - 1)]);
            //添加子节点时，回写上游节点链接关系
            if ($input['type'] == 'addson') {
                $process_id = isset($input['process_id']) ? $input['process_id'] : '';
                $process_to = explode(',', Db::name('wf_process')->field('process_to')->find($process_id)['process_to']);
                array_push($process_to, $newId);
                Db::name('wf_process')->where('id', $process_id)->update(['process_to' => implode(',', $process_to)]);
            }
            if ($res) {
                return $this->success('创建成功', '', $res);
            }
        }
    }
    /**
     * 删除节点
     */
    public function delete_process()
    {
        if (request()->isAjax()) {
            //要删除的节点ID
            $process_id = input('process_id');
            //删除上游关系
            $process_up = $this->get_up($process_id);
            foreach ($process_up as $k => $v) {
                $process_to = explode(',', $v['process_to']);
                $param['process_to'] = implode(',', array_diff($process_to, [$process_id]));
                Db::name('wf_process')->where('id', 'eq', $v['id'])->update($param);
            }
            $res = Db::name('wf_process')->where(['id' => $process_id])->update(['isdelete' => 1]);
            if ($res === false) {
                return $this->error('删除失败');
            } else {
                return $this->success('删除成功');
            }
        }
    }
    /**
     *获取工作流模板相关节点信息
     */
    public function get_process()
    {
        $id = input('id');
        $data = Db::name('wf_flow')->where('id', $id)->field('id as flow_id,total')->find();
        $list = Db::name('wf_process')->where(['flow_id'=>$id,'isdelete'=>0])->field('id,flow_id,process_to,icon,process_name,style')->select();
        $lists = array();
        foreach ($list as $key => $val) {
            foreach ($val as $k => $v) {
                $lists[$val['id']][$k] = $v;
            }
        }
        $data['list'] = (object)$lists;
        return $this->success('', '', $data);
    }
    /**
     *保存审批流可视化链接状态
     */
    public function save_link()
    {
        $put = file_get_contents('php://input');  //接收多维json
        $param = json_decode($put);
        $num = 0;
        foreach ($param as $key => $val) {
            $metadata = $this->object2array($val);   //获取单条元数据
            //查询节点是否为开始节点
            foreach ($metadata['process_to'] as $k => $v) {
                $type = Db::name('wf_process')->field('process_type')->find($v)['process_type'];
                if ($type == 'is_start') {
                    unset($metadata['process_to'][$k]);
                }
            }
            $where['process_to'] = implode(',', $metadata['process_to']);  //处理连线信息
            //处理style信息
            $style = Db::name('wf_process')->field('style')->find($key)['style'];
            $where['style'] = $this->handle_json($metadata, $style);  //替换json
            $res = Db::name('wf_process')->where('id', 'eq', $key)->update($where);
            if ($res == 1 || $res == 0) {
                $num++;
            }
        }
        if ($num == count((array)$param)) {
            return $this->success('保存成功');
        } else {
            $number = count((array)$param) - $num;
            return $this->error('失败了' . $number . '条');
        }
    }
    /**
     * 设为第一步
     */
    public function set_one()
    {
        if (request()->isAjax()) {
            $process_id = input('process_id');
            $param['process_type'] = 'is_start';
            //清除上游节点关系
            $process_up = $this->get_up($process_id);
            foreach ($process_up as $k => $v) {
                $process_to = explode(',', $v['process_to']);
                $param2['process_to'] = implode(',', array_diff($process_to, [$process_id]));
                Db::name('wf_process')->where('id', 'eq', $v['id'])->update($param2);
            }
            //设置当前节点为第一步
            $res = Db::name('wf_process')->where('id', 'eq', $process_id)->update($param);
            if ($res == 1 || $res == 0) {
                return $this->success('设置成功');
            }
            $this->success('设置失败');
        }
    }
    /**
     * 获取当前流程的表单字段信息
     */
    public function get_field()
    {
        if (request()->isAjax()) {
            $flow_id = input('flow_id');  //25
            $process_id = input('process_id');  //86
            $flow = Db::name('wf_flow')->find($flow_id);
            //查询字段当前节点的表单字段信息
//            if($flow['is_form_extend']==2){
                $form_field = Db::name('wf_form_field')->where(['flow_id' => $flow_id])->select();
                //添加当前节点内的选项数据
                $field_type = Db::name('wf_process')->field('write,secret')->find($process_id);
                foreach ($field_type as $k => $v) {
                    $field_type[$k] = explode(',', $v);
                }
                foreach ($form_field as $k => $v) {
                    if (in_array($v['id'], $field_type['write'])) {
                        $form_field[$k]['write'] = 'checked="true"';
                        $form_field[$k]['secret'] = 'disabled="true"';
                    } elseif (in_array($v['id'], $field_type['secret'])) {
                        $form_field[$k]['write'] = 'disabled="true"';
                        $form_field[$k]['secret'] = 'checked="true"';
                    }
                    if (!empty($form_field[$k]['content'])) {
                        $form_field[$k]['content'] = json_decode($v['content'], true);
                    }
                }
//            }else{
//                $form_field = Db::name('wf_form_field')->where(['form_extend_id' => $flow['form_extend_id']])->select();
//            }
            foreach($form_field as $k=>$v){
                $form_field[$k]['is_form_extend'] = $flow['is_form_extend'];
            }
            //获取表单字段所有类型
            $option = Db::name('wf_field_type')->select();
            //msg--类型，data--字段列表
            foreach($form_field as $k=>$v){
                $form_field[$k]['name']=$v['source_table'].'*'.$v['name'];
            }
            return $this->success($option, $flow['is_form_extend'], $form_field);
        }
    }
    /**
     * 修改是否外接表单状态
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function save_switch(){
        if(request()->isAjax()){
            $flow_id = input('flow_id');
            $param['is_form_extend'] = input('type');
            $param['form_extend_id'] = input('form_extend_id');
            $res = Db::name('wf_flow')->where('id','eq',$flow_id)->update($param);
            return $this->success('选择成功','',$res);
        }
    }
    /**
     * 获取有无外接表状态
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_switch(){
        if(request()->isAjax()){
            $flow_id = input('flow_id');
            $res = Db::name('wf_flow')->find($flow_id);
            return $this->success('OK','',$res);
        }
    }
    /**
     * 获取当前节点表单字段设置
     */
    public function field()
    {
        if (request()->isAjax()) {
            $id = input('process_id');
            //节点基本信息
            $res = Db::name('wf_process')->field('write,')->find($id);
            //获取表单字段信息
            $form_field = Db::name('wf_form_field')->whereIn('id', $res['write'])->select();
            return $this->success('', '', $form_field);
        }
    }
    /**
     *新增表单字段
     */
    public function add_field()
    {
        if (request()->isAjax()) {
            $param = $this->filter(input());
            $res = Db::name('wf_form_field')->insert($param);
            return $this->success($res);
        }
    }
    /**
     * 获取人员列表
     */
    public function get_users()
    {
        if (request()->isAjax()) {
            $process_id = input('id');
            $str = input('str');
            $list = Db::name('sys_user')->field('id as value,username as name')->select();
            $data = $this->default_select($process_id, $list, $str);
            return $this->success($data);
        }
    }
    /**
     * 获取角色列表
     */
    public function get_roles()
    {
        if (request()->isAjax()) {
            $process_id = input('id');
            $str = input('str');
            $list = Db::name('sys_role')->field('id as value,rolename as name')->select();
            $data = $this->default_select($process_id, $list, $str);
            return $this->success($data);
        }
    }
    /**
     * 获取部门列表
     */
    public function get_depts()
    {
        if (request()->isAjax()) {
            $process_id = input('id');
            $str = input('str');
            $list = Db::name('sys_dept')->field('id as value,name as name')->select();
            $data = $this->default_select($process_id, $list, $str);
            return $this->success($data);
        }
    }
    /**
     * 获取转出规则
     */
    public function get_con()
    {
        if (request()->isAjax()) {
            $id = input('process_id');
            $process_to = Db::name('wf_process')->field('process_to,out_param')->find($id);
//            $list = Db::name('wf_process')->whereIn('id', $process_to['process_to'])->field('id,option,desc')->select();
            $list = json_decode($process_to['out_param'],true);
            $data = array();
            foreach ($list as $k => $v) {
                $v['option'] = $this->filter(explode("\n", $v['option'])); //切割成数组
                foreach ($v['option'] as $l => $n) {
                    //准备一套=链接的条件方便数据处理
                    $replace = array('<>','>','<','>=','<=','==','include','exclude');
                    $ns = str_replace($replace,'=',$n);
                    $field_id = str_replace("'", '', trim(substr($ns, 0, strrpos($ns, "="))));
                    $field = explode('*',$field_id);//[0]表名，[1]字段名
                    $field_name = $this->get_field_name($field);    //查询
                    $v['option'][$l] = array(
                        'value' => str_replace(array("\r\n", "\r", "\n"), "", $n),
                        'html' => str_replace(array("\r\n", "\r", "\n"), "", str_replace($field_id,$field_name['source_table'].'*'.$field_name['name'],$n)),
                    );
                }
                $data[$v['id']] = $v;
            }
            $res = array(
                'msg'=>'',
                'code'=>200,
                'data'=>$data,
            );
            return json($res);
        }
    }
    /**
     * 获取初始化样式
     */
    public function get_style()
    {
        if (request()->isAjax()) {
            $id = input('process_id');
            $style = Db::name('wf_process')->where('id', 'eq', $id)->field('style')->find()['style'];
            $style = json_decode($style, true);
            return $this->success('', '', $style);
        }
    }
    /**
     * 保存节点属性变更
     */
    public function save_attribute()
    {
        if (request()->isPost()) {
            $input = input();
            $param = array();    //--修改当前节点参数
            $param['process_name'] = $input['process_name'];                    //节点名
            $param['process_type'] = $input['process_type'];                    //节点类型
            if (isset($input['process_to'])) {
                $param['process_to'] = implode(',', $input['process_to']);  //下游节点
            }
            $param['auto_person'] = $input['auto_person'];                      //审核权限预设
            $param['auto_unlock'] = isset($input['auto_unlock']) ? $input['auto_unlock'] : '0';  //是否可修改审核权限预设
//            $param['auto_sponsor_uids'] = $input['auto_sponsor_uids'];          //指定主办人
//            $param['auto_respon_uids'] = $input['auto_respon_uids'];            //指定经办人
//            $param['auto_role_ids'] = $input['auto_role_ids'];                  //指定角色
            $param['range_user_ids'] = $input['range_user_ids'];                //授权人员
            $param['range_dept_ids'] = $input['range_dept_ids'];                //授权部门
            $param['range_role_ids'] = $input['range_role_ids'];                //授权角色
            $param['con_sign'] = $input['con_sign'];                            //会签方式
            $param['con_sign_vsb'] = $input['con_sign_vsb'];                    //是否可见
            $param['con_sign_back'] = $input['con_sign_back'];                  //回退方式
            $param['is_comment'] = isset($input['is_comment']) ? $input['is_comment'] : 0;                        //是否需要评论  1，是 |0，否
            $param['is_upload'] = isset($input['is_upload']) ? $input['is_upload'] : 0;                          //是否可以上传附件 1，是 |0，否
            $param['is_head'] = isset($input['is_head']) ? $input['is_head'] : 0;                              //授权部门时，是否为该部门主管 1，是 |0，否
            $param['write'] = isset($input['write']) ? implode(',', $this->match_element('data_', $input['write'], 'value', true)) : '';  //可写字段id串
            $param['secret'] = isset($input['secret']) ? implode(',', $this->match_element('data_', $input['secret'], 'value', true)) : ''; //保密字段id串
            //处理style参数
            $json = Db::name('wf_process')->field('style')->find($input['id'])['style'];
            $array = json_decode($json, true);
            $style = $this->match_element('style_', $input, 'key', true);
            foreach ($style as $k => $v) {
                $array[$k] = $v;    //没则添加，有则修改
            }
            $param['style'] = json_encode($array);   //样式数据
            //组装审批流表单条件
            $field_prm = array();
            $field_type = $this->match_element('field_type_', $input, 'key', true); //修改表单字段类型参数
            $field_content = $this->match_element('option_', $input, 'key', true);
            foreach ($field_type as $key => $val) {
                $field_prm[$key]['field_type'] = $val;
                if ($val != 1) {   //类型不为文本框
                    $field_prm[$key]['content'] = json_encode($field_content[$key]);
                } elseif ($val == 1) {
                    $field_prm[$key]['content'] = '';
                }
            }
            //转出规则条件处理
            $out_prm = array();
            foreach ($input as $k => $v) {
                if (strpos($k, 'process_in_set_') !== false) {
                    $out_prm[str_replace('process_in_set_', '', $k)]['id'] = str_replace('process_in_set_', '', $k);
                    $out_prm[str_replace('process_in_set_', '', $k)]['option'] = $v;
                } elseif (strpos($k, 'process_in_desc_') !== false) {
                    $out_prm[str_replace('process_in_desc_', '', $k)]['desc'] = $v;
                }
            }
            unset($out_prm['@a']);
            $param['out_param'] =  json_encode($out_prm);  //当前节点写入出口规则
            foreach ($field_prm as $k => $v) {
                Db::name('wf_form_field')->where('id', $k)->update($v);  //更新表单字段类型
            }
            $res = Db::name('wf_process')->where('id', 'eq', $input['id'])->update($param);  //更新节点表--当前节点
            if ($res == 1 || $res == 0) {
                return $this->success('设置成功');
            } else {
                return $this->error('设置失败');
            }
        }
    }
    /*********************************************************************流程页面**********************************************************************/
    /**
     *获取外接表单列表
     */
    public function get_form_extend()
    {
        if (request()->isAjax()) {
            $flow_id = input('flow_id');
            $res = Db::name('wf_form_extend')->field('id as value,china_name as name')->where(['isdelete' => 0])->select();
            $basic = Db::name('wf_flow')->field('form_extend_id')->find($flow_id);
            foreach ($res as $k => $v) {
                if ($v['value']==$basic['form_extend_id']) {
                    $res[$k]['selected'] = true;
                }
            }
            return $this->success('', '', $res);
        }
    }
    /**
     * 用于判断是否为外接表信息
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function judge_form_extend(){
        if(request()->isAjax()){
            $flow_id = input('flow_id');
            $data = Db::name('wf_flow')->find($flow_id);
            if($data['is_form_extend']==1){
                $form_extend = Db::name('wf_form_extend')->find($data['form_extend_id']);
                $data['value']= $form_extend['controller'].'/'.$form_extend['action'];
            }
            return $this->success('成功提取信息','',$data);
        }
    }
    /**
     *获取外接表单链接 /控制器和方法/
     */
    public function form_extend_detil(){
        if(request()->isAjax()){
            $form_id = request()->post('form_id');
            $workflow_id = request()->post('workflow_id');
            $data = Db::name('wf_form_extend')->where(['isdelete'=>0])->find($form_id);
            $res = Db::name('wf_workflow')->where(['isdelete'=>0,'id'=>$workflow_id])->find();
            $data['form_extend'] = $res['form_extend'];
            $data['value']= $data['controller'].'/'.$data['action'];
            return $this->success('抓取成功','',$data);
        }
    }
    /**
     *获取审批表单
     */
    public function get_workflow_form_data()
    {
        if (request()->isAjax()) {
            $workflow_id = input('worlflow_id');
            $field = $this->count_next_process($workflow_id);  //获取表单字段配置，字段数据，当前节点字段填写规则
            return $this->success('查询成功', '', $field);
        }
    }
    /**
     * 获取工作流详情页
     */
    public function get_detail_flow()
    {
        if (request()->isAjax()) {
            $workflow_id = input('id');
            $data = $this->get_time_line($workflow_id);
            return $this->success('查询成功', '', $data);
        }
    }
    /**
     * 验证是否有正在使用该模版的流程
     */
    public function check_flow()
    {
        if (request()->isAjax()) {
            $workflow_id = input('id');
            $audit_status = Db::name('wf_workflow')->find($workflow_id)['audit_status'];
            if (!empty($audit_status)) {
                return $this->success($audit_status);
            }
            return $this->error('no');
        }
        return $this->error('no');
    }
    /**
     * 获取审批流列表页列表  --1，自发起 --2，待审核
     */
    public function get_workflow_list()
    {
        if (request()->isAjax()) {
            $type = input('type');
            if ($type == 1) {
                $where = array(
                    'wo.sponsor' => $this->now_user,
                    'wo.isdelete'=>0
                );
                $list = Db::name('wf_workflow')->alias('wo')
                    ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left')
                    ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left')
                    ->join('wf_process p','wp.process_id = p.id','left')
                    ->join('sys_user u','u.id=wo.sponsor','left')
                    ->field('wo.id as id,fl.name as name,wo.flow_id as flow_id,u.username as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend')
                    ->where($where)
                    ->order('wo.id','asd')
                    ->select();
                //循环替换审核人名
                foreach($list as $key=>$val){
                    $peoples = Db::name('sys_user')->whereIn('id',explode(',',$val['peoples']))->field('username')->select();
                    foreach($peoples as $k=>$v){
                        $peoples[$k] = $v['username'];
                    }
                    $list[$key]['peoples'] = implode(',',$peoples);
                }
            } elseif ($type == 2) {
                $where = array(
                    'examine_people' => $this->now_user,
                    'status' => 0,  //未操作，需要操作
                    'isdelete'=>0
                );
                //去重查询出所有待审核操作涉及的流程ID
                $examineall = Db::name('wf_examine')->where($where)->distinct(true)->field('workflow_id')->order('workflow_id desc')->select();
                foreach ($examineall as $k => $v) {
                    $examineall[$k] = $v['workflow_id'];
                }
                //查询相关流程
                $list = Db::name('wf_workflow')->alias('wo')
                    ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left')
                    ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left')
                    ->join('wf_process p','wp.process_id = p.id')
                    ->join('sys_user u','u.id=wo.sponsor','left')
                    ->field('wo.id as id,fl.name as name,wo.flow_id as flow_id,u.username as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend')
                    ->where(['audit_status' => 1,'wo.isdelete'=>0])
                    ->whereIn('wo.id', $examineall)  //根据符合的流程id查询
                    ->order('wo.id','asd')
                    ->select();
                //循环替换审核人名
                foreach($list as $key=>$val){
                    $peoples = Db::name('sys_user')->whereIn('id',explode(',',$val['peoples']))->field('username')->select();
                    foreach($peoples as $k=>$v){
                        $peoples[$k] = $v['username'];
                    }
                    $list[$key]['peoples'] = implode(',',$peoples);
                }
            }
            foreach ($list as $key => $val) {
                if(!empty($val['form_extend_id'])){
                    $extend = Db::name('wf_form_extend')->find($val['form_extend_id']);
                    if(!empty($extend)){
                        $list[$key]['index'] = $extend['controller'].'/'.$extend['indexs'];
                        $list[$key]['add'] = $extend['controller'].'/'.$extend['adds'];
                        $list[$key]['edit'] = $extend['controller'].'/'.$extend['edits'];
                    }
                }
            }
            $data = array(
                'code' => '200',
                'msg' => '请求成功',
                'count' => count($list),
                'data' => $list,
            );
            return $data;
        }
    }
    /**
     * 获取审批流模版下拉列表
     */
    public function get_flowlist()
    {
        if (request()->isAjax()) {
            $res = Db::name('wf_flow')->field('id as value,name as name')->select();
            return $this->success('', '', $res);
        }
    }
    /**
     * 获取流程表单的配置
     */
    public function get_formconfig()
    {
        if (request()->isAjax()) {
            $where = $this->filter(input());//模版ID
            //获取模版表单
            $form_field = $this->get_flow_field($where);
            //获取附加限制
            $process = Db::name('wf_process')->where(['flow_id'=>$where['flow_id'],'process_type'=>'is_start'])->field('is_comment,is_upload,flow_id')->find();
            return $this->success($process, '', $form_field);
        }
    }
    /**
     * 拓印表单数据
     * @param $flow
     * @param $form_extend
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_formdata($flow,$form_extend){
        $form_extends = Db::name('wf_form_extend')->find($flow['form_extend_id']);//外接表名
        $field_list = Db::name('wf_flow')->alias('f')
            ->join('wf_form_field ff','f.form_extend_id=ff.form_extend_id','inner')
            ->field('ff.id as id,ff.extend_field as extend_field')
            ->select();
        $array = array();
        foreach($field_list as $k=>$v){
            $array[] = Db::name($form_extends['code_name'])->where(['id'=>$form_extend])->field($v['extend_field'])->find();
        }
        return $array;
    }
    /**
     * 发起流程
     */
    public function save_workflow()
    {
        if (request()->isAjax()) {
            $put = file_get_contents('php://input');  //接收多维json
            $json = json_decode($put);
            $array = $this->object2array($json);
            if(empty($array)){
                $array=request()->post();
            }
            $flow_id = $array['flow_id'];
            //查询模板信息进行分类处理
            $flow = Db::name('wf_flow')->find($flow_id);
            //组装流程表数据
            $param = array();
            if($flow['is_form_extend']==0){
                //查询字段信息
                $formdata = $array;
                foreach ($formdata as $k => $v) {
                    if ($v == 'on') {
                        $formdata[$k] = "true";
                    }
                }
                unset($formdata['content']);
                unset($formdata['file']);
                unset($formdata['flow_id']);
            }elseif($flow['is_form_extend']==1){
                $param['form_extend'] = $array['form_extend'];
                $formdata = $this->get_formdata($flow,$array['form_extend']);
            }
            $param['formdata'] = json_encode($formdata);  //存储表单数据
            $param['file_ids'] = implode(',',$this->match_element('file_ids',$array,'key',true));
            $param['flow_id'] = $flow_id;              //存储表单数据
            $param['sponsor'] = $this->now_user;   //发起人
            $param['isdelete'] = 0;                    //是否删除
            $param['audit_status'] = 1;                //流程审批状态
            //写入流程表
            $workflow_res = Db::name('wf_workflow')->insert($param);
            $workflow_id = Db::name('wf_workflow')->getLastInsID();
            /*******************分配审批流数据节点(初始化)*********************/
            $process = Db::name('wf_process')->where('flow_id', 'eq', $flow_id)->select();  //查询模版节点信息
            $workprocess_param = array();
            foreach ($process as $k => $v) {
                $workprocess_param[$k]['workflow_id'] = $workflow_id;            //工作流ID
                $workprocess_param[$k]['process_id'] = $v['id'];                 //模版节点ID
                $workprocess_param[$k]['con_sign'] = $v['con_sign'];             //节点审批模式
                if ($v['process_type'] == 'is_start') {
                    $workprocess_param[$k]['node_status'] = 1;                   //节点审核状态
                } else {
                    $workprocess_param[$k]['node_status'] = 0;
                }
                $workprocess_param[$k]['is_delegate'] = 0;                       //是否进行了委派
                $workprocess_param[$k]['legate_users'] = '';                     //委派人员/人员集
                $workprocess_param[$k]['legate_roles'] = '';                     //委派角色/角色集
                $workprocess_param[$k]['legate_depts'] = '';                     //委派部门/部门集
                $workprocess_param[$k]['isdelete'] = 0;
            }
            Db::name('wf_workprocess')->insertAll($workprocess_param);  //入库
            /***************************循环插入审核人id**************************/
            foreach ($process as $k => $v) {
                $where = array(
                    'workflow_id' => $workflow_id,
                    'process_id' => $v['id'],
                );
                if($v['process_type'] =='is_start' || $v['process_type'] =='is_end' ){
                    $peoples = null;
                }else{
                    $peoples = $this->seek_people($workflow_id, $v['id']); //查找审核人
                    Db::name('wf_workprocess')->where($where)->update(['peoples' => (int)$peoples]);
                }
            }
            /*******************获取起始流程节点信息和下一步流程节点信息*****************/
            $first_workprocess = $this->get_some_process($workflow_id,'first');  //获取起始节点信息 一维数组
            $workprocess = $this->get_some_process($first_workprocess['id'],'next');  //获取下一节点
            /****************回写起始节点和下一节点id到流程表以及下一节点的来源ID*****************/
            Db::name('wf_workflow')->where('id', 'eq', $workflow_id)->update(['first_workprocess_id' => $first_workprocess['id'], 'next_workprocess_id' => $workprocess['id']]);
            Db::name('wf_workprocess')->where('id','eq',$workprocess['id'])->update(['source_node'=>$first_workprocess['id']]);
            /*********************流程信息查询*******************/
            $workflow = Db::name('wf_workflow')->find($workflow_id);
            /*********************写入消息表***********************/
            exit;
            $this->create_news($workflow, $workprocess, 'create');
            /*********************写入审核操作表*********************/
            $this->create_examine($workprocess);
            /*********************写入日志表*************************/
            $content = isset($array['content'])?$array['content']:'';
            $this->create_log($workflow, $content, 'create');
            return $this->success('成功发起流程', '', $workflow_res);
        }
    }
    /**
     * 审批操作  修改流程表状态 节点数据表状态
     */
    public function to_examine_workflow()
    {
        if (request()->isAjax()) {
            $input = request()->post();
            //获取审核人  ---当前审核人（登陆人）
              $user = $this->now_user;
            if(isset($input['file_ids'])){
                $file_ids = implode(',',$input['file_ids']);
                //加入新的附件
                $file =  Db::name('wf_workflow')->field('file_ids')->find($input['workflow_id']);
                Db::name('wf_workflow')->where(['id'=>$input['workflow_id']])->update(['file_ids'=>$file['file_ids'].','.$file_ids]);
            }
            $workprocess = Db::name('wf_workprocess')->find($input['next_workprocess_id']); //当前审核节点信息
            if ($workprocess['node_status'] == 1) {
                return $this->error('您访问的流程已操作或已失效');
            }
            if ($input['type'] == 'next') {
                $this->next($input);
            }
            if ($input['type'] == 'previous') {
                $this->previous($input);
            }
            if ($input['type'] == 'first') {
                $this->first($input);
            }
            return $this->success('操作成功');
        }
    }
    /**
     * 撤回
     */
    public function recall_work_flow(){
        if(request()->isAjax()){
            $workflow_id = input('id');
            $data = Db::name('wf_workflow')->find($workflow_id);
            //1，结束所有审核操作
            Db::name('wf_examine')->where(['workflow_id'=>$workflow_id])->update(['node_status'=>1,'status'=>1]);
            //2，重置所有节点状态
            Db::name('wf_workprocess')->where(['workflow_id'=>$workflow_id])->update(['node_status'=>0]);
            //3，重置流程状态为3 && 下一节点变为起始节点
            Db::name('wf_workflow')->where(['id'=>$workflow_id])->update(['audit_status'=>4,'next_workprocess_id'=>$data['first_workprocess_id']]);
            //写入操作日志
            $this->create_log($data,'','recall');
            return $this->success('成功撤回');
        }
    }
    /**
     * 获取编辑流程表单需要的默认值
     */
    public function get_workflow_default(){
        if (request()->isAjax()) {
            $workflow_id = input('worlflow_id');
            $field = $this->count_next_process($workflow_id);  //获取表单字段配置，字段数据，当前节点字段填写规则
            return $this->success('查询成功', '', $field);
        }
    }
    /**
     * 删除附件
     */
    public function down_list_del(){
        if(request()->isAjax()){
            $id = input('id');
            $res = Db::name('wf_files')->where(['id'=>$id])->update(['isdelete'=>1]);
            if($res !== false){
                return $this->success('删除成功');
            }else{
                return $this->error('删除失败');
            }
        }
    }
    /**
     * 重新发起
     */
    public function edit_workflow(){
        if(request()->isAjax()){
            $put = file_get_contents('php://input');  //接收多维json
            $json = json_decode($put);
            $input = $this->object2array($json);
            if(empty($input)){
                $input['workflow_id'] = request()->post('workflow_id');
            }
            $workflow = Db::name('wf_workflow')->where(['id'=>$input['workflow_id']])->find();
            //获取workflow_id 相关判断值
            $flow = Db::name('wf_flow')->where(['id'=>$workflow['flow_id']])->find();
            //组装流程表数据
            $param = array();
            if($flow['is_form_extend']==1){
                $param['form_extend'] = $workflow['form_extend'];
                $array = $this->get_formdata($flow,$workflow['form_extend']);
            }else{
                //处理修改后的附件
                $field = $this->match_element('file_id',$input,'key',true);
                $param['file_ids'] = implode(',',$field);
                //处理修改后的表单数据
                $array = $this->match_element('field_',$input,'key',false);
                foreach ($array as $k => $v) {
                    if ($v == 'on') {
                        $array[$k] = "true";
                    }
                }
            }
            $param['formdata'] = json_encode($array);  //存储表单数据
            $param['audit_status'] = 1;
            //修改初始节点状态
            Db::name('wf_workprocess')->where(['id'=>$workflow['first_workprocess_id']])->update(['node_status'=>1]);
            //修改流程表
            Db::name('wf_workflow')->where(['id'=>$input['workflow_id']])->update($param);
            //根据新数据重新验证下一节点的选择
            $workprocess = $this->get_some_process($workflow['first_workprocess_id'],'next');
            //修改初始节点状态
            Db::name('wf_workprocess')->where(['id'=>$workflow['first_workprocess_id']])->update(['node_status'=>1]);
            //回写下一审核节点
            Db::name('wf_workflow')->where(['id'=>$input['workflow_id']])->update(['next_workprocess_id'=>$workprocess['id']]);
            /****************************流程信息查询*************************/
            $workflow = Db::name('wf_workflow')->find($input['workflow_id']);
            /*********************写入消息表***********************/
            $this->create_news($workflow, $workprocess, 'create');
            /*********************写入审核操作表*********************/
            $this->create_examine($workprocess);
            /*********************写入日志表*************************/
            $content = isset($input['content'])?$input['content']:'';
            $this->create_log($workflow, $content, 'repeat');
            return $this->success('成功发起流程');
        }
    }
    /**
     *获取当前流程进度示意图数据
     */
    public function get_progress(){
        if(request()->isAjax()){
            $workflow_id = input('id');
            $list = Db::name('wf_workprocess')->alias('wp')
                ->join('wf_process p','wp.process_id = p.id','left')
                ->where(['wp.workflow_id'=>$workflow_id])
                ->field('wp.id,wp.process_id,wp.workflow_id,p.process_to,p.process_type,p.process_name title')
                ->select();
            foreach($list as $k=>$v){
                if(strpos($v['process_to'],',')){
                    $data = $this->get_some_process($v['id'],'next'); //下一节点信息
                    $str_arr = explode(',',$v['process_to']);
                    foreach( $str_arr as $key=>$val) {
                        if($data['process_id'] != $val){
                            foreach($list as $keys=>$vals){
                                if($vals['process_id']==$str_arr[$key]){
//                                    unset($list[$keys]); //清除list中不需要的分支
                                    $list[$k]['process_to']=$data['process_id'];//回写process_to
                                }
                            }
                        };
                    }
                }
            }
            //查询流程当前节点的ID
            $workflow = Db::name('wf_workflow')->find($workflow_id);
            $now = '';
            $list = $this->level_order($list);  //递归加层排序
            foreach($list as $k=>$v){
                $res = Db::name('wf_log')->alias('l')
                    ->join('sys_user u','u.id=l.operator','left')
                    ->where(['l.workflow_id'=>$v['workflow_id'],'l.workprocess_id'=>$v['id']])
                    ->field('l.content,l.create_time,u.username')
                    ->order('l.id','desc')
                    ->find();
                $list[$k]['content'] = $res['content'];
                $list[$k]['create_time'] = $res['create_time'];
                $list[$k]['username'] = $res['username'];
                if($v['id'] == $workflow['next_workprocess_id']){
                    $now = $v['level']+1;
                }
                $list[$k]['level'] = $v['level']+1;
            }
            if($workflow['audit_status']==2){
                $now = count($list);
            }
        $array = array(
            'list' => $list,
            'now' =>$now,
        );
        return $this->success('查询成功','',$array);
        }
    }
    /*********************************************************************杂乱方法*********************************************************************/
    /**
     * 按需返回节点信息
     * @param $id_str
     * @param $type   first  back  next  last
     * @return array|bool|false|\PDOStatement|string|\think\Collection|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_some_process($id_str,$type){
        $workflow_id = $id_str;
        $workprocess_id = $id_str;
        $data = array();
        switch ($type){
            case 'first':
                //查询起始节点 --条件为$workflow_id
                $data = Db::name('wf_workflow')->alias('wf')
                    ->join('wf_workprocess wp','wf.id = wp.workflow_id','left')
                    ->join('wf_process p','wp.process_id=p.id')
                    ->where(['wp.workflow_id'=>$workflow_id,'p.process_type'=>'is_start'])
                    ->field('wp.*')
                    ->find();
                break;
            case 'back':
                //查询上个节点 --获取的是$workprocess_id
                $back_workprocess_id = Db::name('wf_workprocess')->where(['id'=>$workprocess_id])->field('source_node')->find()['source_node'];
                $data = Db::name('wf_workprocess')->where(['id'=>$back_workprocess_id])->find();
                break;
            case 'next':
                //查询下个节点 --获取的是$workprocess_id
                $select = Db::name('wf_workprocess')->field('workflow_id')->find($workprocess_id);
                $next_process_id = $this->judge_next_choice($workprocess_id);
                $data = Db::name('wf_workprocess')->where(['workflow_id'=>$select['workflow_id'],'process_id'=>$next_process_id])->find();
                break;
            case 'last':
                //查询末尾节点 --获取的是$workflow_id
                $data = Db::name('wf_workflow')->alias('wf')
                    ->join('wf_workprocess wp','wf.id = wp.workflow_id','left')
                    ->join('wf_process p','wp.process_id=p.id')
                    ->where(['wf.id'=>$workflow_id,'p.process_type'=>'is_end'])
                    ->field('wp.*')
                    ->find();
                break;
        }
        return $data;
    }
    /**
     * 根据流程表单中的值自动识别下一步并且返回下一步模板节点ID
     * @param $workprocess_id  当前工作流节点
     * @return bool|int|mixed|string  下一节点ID或者false（异常）
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function judge_next_choice($workprocess_id=606){
        $retutn_id = '';
        $workprocess_data = Db::name('wf_workprocess')->alias('wp')
            ->join('wf_process p','p.id = wp.process_id','left')
            ->where(['wp.id'=>$workprocess_id])
            ->field(['p.process_to,p.flow_id,wp.workflow_id,p.out_param'])  //获取下级节点列表列表，流程模板ID，流程ID
            ->find();
//        $process = Db::name('wf_process')->whereIn('id',explode(',',$workprocess_data['process_to']))->select(); //下一节点的模板节点ID
        $process = json_decode($workprocess_data['out_param'],true);
        if(count($process)<=1){
            $num =  end($process)['id'];
            return $num;  //下级节点只有一个时直接返回
        }
        $array = array();
        /**
         * 这里没有处理好↓
         * 导致无法多条件判断 没有and和or的判断
         */
        foreach($process as $key=>$val){
            $reg = "/(AND|OR)+?/";  //两个空格之间是数字的正则
            preg_match($reg,$val['option'],$out);
            $array[$val['id']] = preg_split($reg,$val['option']);
        }
//        echo '<pre>';
//        print_r($process);
//        echo '</pre>';
//        echo '<pre>';
//        print_r($array);
//        echo '</pre>';
//        exit;
        /**
         * 这里没有处理好↑
         */
        $flow = Db::name('wf_flow')->find($workprocess_data['flow_id']);
        $workdata = Db::name('wf_workflow')->find($workprocess_data['workflow_id']);//获取当前节点在流程的form表单信息 （分歧点，自表差流程表，外表读数据）
        if($flow['is_form_extend'] == 1){
            $form_datas = Db::name($flow['table_name'])->find($workdata['form_extend']); //根据外接表单的表名和数据ID获取数据
            $user_data = Db::name('sys_user')->find($workdata['sponsor']); //获取发起人信息
            $re_array = Db::name('wf_form_field')->where(['isdelete'=>0,'flow_id'=>$workprocess_data['flow_id']])->field('id,field_name,source_table')->select();
            $form_data = array();
            foreach($form_datas as $key=>$val){
                foreach($re_array as $k=>$v){
                    if($v['field_name']==$key && $v['source_table']==$flow['table_name']){
                        $form_data[$v['id']]=$val;
                    }
                }
            }
            foreach($user_data as $key=>$val){
                foreach($re_array as $k=>$v){
                    if($v['field_name']==$key && $v['source_table']=='sys_user'){
                        $form_data[$v['id']]=$val;
                    }
                }
            }
        }else{
            $form_data = json_decode($workdata['formdata'],true);  //--这是表单json
            $form_data = $this->match_element('field_',$form_data,'key',true);
        }
        $default = array();  //--将空值设为默认
        foreach($array as $k=>$v){
            if(empty($v[0])){
                $default =$k;
                continue;
            }
            foreach($v as $key=>$val){
                $warray = $this->filter(explode("'",$val));
                if($flow['is_form_extend'] == 1){
                    $param = explode('*',$warray[1]);
                    $field_id = Db::name('wf_form_field')->where(['source_table'=>$param[0],'field_name'=>$param[1]])->find()['id'];
                    $warray[1] = $field_id;
                    $wk = $warray;
                }else{
                    $wk = $this->match_element('data_',$warray,'value',true);
                }
                //对比当前节点判断的字段 在填写报表数据里是否有对应值，有的话取出对比
                if(array_key_exists($wk[1],$form_data)){
                    $field = Db::name('wf_form_field')->field('content')->find($wk[1]);
                    if(!empty($field['content'])){
                        $form_data_field = json_decode($field['content'],true);
                        $res = $this->val_compare($warray,$form_data_field[$form_data[$wk[1]]]);
                    }else{
                        $res = $this->val_compare($warray,$form_data[$wk[1]]);
                    }
                    if($res == 1){
                        $retutn_id = $k;
                    }
                }else{
                    return false;  //需要填写审核用的必要数据短缺（数据异常）
                }
            }
            if(!empty($retutn_id)){
                break;
            }
        }
        if(empty($retutn_id)){
            $retutn_id = $default; //没有匹配到则取默认节点
        }
        return $retutn_id;
    }
    /**
     * 比较选择返回
     * @param $array
     * @param $str
     */
    public function val_compare($array,$str){
        switch ($array[2]){
            case ' = ' :
                if(end($array) == $str){
                    return 1;
                }else{
                    return  0;
                };
                break;
            case ' <> ' :
                if(end($array) <> $str){
                    return  1;
                }else{
                    return  0;
                };
                break;
            case ' > ' :
                if(intval($str) > intval(end($array))){
                    return  1;
                }else{
                    return  0;
                };
                break;
            case ' < ' :
                if(intval($str) < intval(end($array))){
                    return  1;
                }else{
                    return  0;
                };
                break;
            case ' >= ' :
                if(intval($str) >= intval(end($array))){
                    return  1;
                }else{
                    return  0;
                };
                break;
            case ' <= ' :
                if(intval($str) <= intval(end($array))){
                    return  1;
                }else{
                    return  0;
                };
                break;
            case ' include ' :
                if(strstr(end($array),$str) === false){
                    return  0;
                }else{
                    return  1;
                };
                break;
            case ' exclude ' :
                if(strstr(end($array),$str) === false){
                    return  1;
                }else{
                    return  0;
                };
                break;
        }
    }
    /**
     * 根据流程ID查询接下来要审核的节点字段信息
     */
    public function count_next_process($workflow_id)
    {
        //补充操作id
        $ex_id = Db::name('wf_examine')->where(['examine_people' => $this->now_user, 'status' => 0])->find();
        $workflow = Db::name('wf_workflow')->find($workflow_id);  //选中流程信息   $workflow['formdata'] 当前表单数据
        $workflow['ex_id'] = $ex_id['id'];
        $workprocess = Db::name('wf_workprocess')->find($workflow['next_workprocess_id']);//查找下一需审核节点信息 当前模型节点ID $workflow['next_workprocess_id'];
        //获取附加限制
        $process = Db::name('wf_process')->where(['flow_id'=>$workflow['flow_id'],'id'=>$workprocess['process_id']])->field('is_comment,is_upload')->find();
        $workflow['is_comment'] = $process['is_comment'];
        $workflow['is_upload'] = $process['is_upload'];
        $form_fields = $this->get_flow_field(['flow_id' => $workflow['flow_id']]);  //表单字段信息查询
        $process = Db::name('wf_process')->find($workprocess['process_id']);
        $form_config = explode(',', $process['write']); //当前节点的表单展示规则
        $downlist = $this->get_down_list($workflow_id);
        $res = array(
            'msg' => $workflow,
            'data' => $form_fields,            //表单字段配置
            'form_data' => json_decode($workflow['formdata'], true),  //表单数据  field_+id
            'form_config' => $form_config,      //当前节点可写配置
            'process' => $process,              //节点配置
            'downlist'=>$downlist,
        );
        return $res;
    }
    /**
     * 获取字段名字
     * @param string|array $id
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_field_name($id)
    {
        if(is_array($id)){
            $res = Db::name('wf_form_field')->where(['source_table'=>$id[0],'field_name'=>$id[1]])->find();
        }else{
            $res = Db::name('wf_form_field')->field('field_name')->where('id', 'eq', $id)->find()['field_name'];
        }
        return $res;
    }
    /**
     * 获取上级节点
     */
    public function get_up($id)
    {
        $flow_id = Db::name('wf_process')->field('flow_id')->find($id)['flow_id'];
        $process_list = Db::name('wf_process')->where('flow_id', 'eq', $flow_id)->field('id,process_to')->select();
        $data = array();
        foreach ($process_list as $k => $v) {
            if (in_array($id, [$v['process_to']])) {
                $data[] = $v;
            }
        }
        return $data;
    }
    /**
     *  打回上一步
     *
     *1，修改工作流的当前节点
     *2，并且修改上一个节点的状态
     *3，修改审核操作表当前节点的所有相关审核状态(使其作废) node_status=1  |status=1
     *4，重新发布上一步审核操作需求
     *5，如果回到原点则修改工作流状态
     *
     */
    public function previous($data)
    {
        $content = isset($data['content'])?$data['content']:'';
        $workprocess = Db::name('wf_workprocess')->find($data['next_workprocess_id']); //当前节点信息
        $workflow = Db::name('wf_workflow')->find($workprocess['workflow_id']); //当前流程信息
        //先修改当前操作记录的操作类型
        Db::name('wf_examine')->where(['workflow_id' => $data['workflow_id'], 'workprocess_id' => $data['next_workprocess_id']])->update(['node_status' => 1, 'status' => 1]);//修改当前节点的所有相关审核
        //重新发布新的审核操作-通知-日志
        $workprocess2 = $this->get_some_process($workprocess['id'],'back'); //查询上一个节点
        //判断上一步节点是否为原点
        $process2 = Db::name('wf_process')->find($workprocess2['process_id']);
        if ($process2['process_type'] == 'is_start') {
            Db::name('wf_workprocess')->where('id', 'eq', $workprocess2['id'])->update(['node_status' => 0]);  //修改上一个节点状态
            Db::name('wf_workflow')->where('id', 'eq', $data['workflow_id'])->update(['next_workprocess_id' => $workprocess2['id'], 'audit_status' => 3]);//回退到起始结点，（关闭）
            $this->create_log($workflow, $content, 'repulse'); //写入日志--当前操作日志
            $this->create_news($workflow, $workprocess2, 'repulse'); //写入消息--通知发起人
        } else {
            Db::name('wf_workprocess')->where('id', 'eq', $workprocess2['id'])->update(['node_status' => 0]);  //修改上一个节点状态
            Db::name('wf_workflow')->where('id', 'eq', $data['workflow_id'])->update(['next_workprocess_id' => $workprocess2['id']]);//只修改下一个审核的节点ID
            $this->create_examine($workprocess2);
            $this->create_log($workflow, $content, 'repulse'); //写入日志--当前操作日志
            $this->create_news($workflow, $workprocess2, 'adopt'); //写入消息--通知下一节点的所有审核人
        }
    }
    /**
     *打回原点
     */
    public function first($data)
    {
        $content = isset($data['content'])?$data['content']:'';
        $workflow = Db::name('wf_workflow')->find($data['workflow_id']); //当前流程信息
        $first_workprocess = $this->get_some_process($data['workflow_id'],'first');
        $notwhere = array();
        array_push($notwhere,$first_workprocess['id']);
        Db::name('wf_examine')->where(['workflow_id' => $data['workflow_id'], 'workprocess_id' => $data['next_workprocess_id']])->update(['node_status' => 1, 'status' => 1]);//修改当前节点的所有相关审核
        Db::name('wf_workprocess')->where(['workflow_id' => $data['workflow_id']])->whereNotIn('id',$notwhere)->update(['node_status' => 0]);
        //发布-通知-日志
        Db::name('wf_workflow')->where('id', 'eq', $data['workflow_id'])->update(['next_workprocess_id' => $first_workprocess['id'], 'audit_status' => 3]);//回退到起始结点，（关闭）
        $this->create_log($workflow, $content, 'repulse'); //写入日志--当前操作日志
        $this->create_news($workflow, $first_workprocess, 'repulse'); //写入消息--通知发起人
    }
    /**
     *审批通过
     */
    public function next($data)
    {
        $content = isset($data['content'])?$data['content']:'';
        $workprocess = Db::name('wf_workprocess')->find($data['next_workprocess_id']); //当前节点信息
        $process = Db::name('wf_process')->find($workprocess['process_id']);//当前模型节点
        $workflow = Db::name('wf_workflow')->find($workprocess['workflow_id']);
        //查询流程当前审核情况
        $con_sign = $process['con_sign'];     //审核类型
        if ($con_sign == 2 || $con_sign == 1) {              //非会签（指定单人，直接审核）或者 单一会审
            //修改对应的操作记录
            Db::name('wf_workprocess')->where(['id' => $data['next_workprocess_id']])->update(['node_status' => 1]);   //先修改当前审批节点状态
            Db::name('wf_examine')->where(['workflow_id' => $workprocess['workflow_id'], 'workprocess_id' => $workprocess['id'], 'status' => 0])->update(['status' => 1, 'node_status' => 1]);  //标识操作记录为已经操作
            //查询下一节点的节点类型
            $workprocess2 = $this->get_some_process($workprocess['id'],'next');  //获取下一节点
            $process2 = Db::name('wf_process')->find($workprocess2['process_id']);
            if ($process2['process_type'] == 'is_end') { //没有下一级
                Db::name('wf_workflow')->where('id', $data['workflow_id'])->update(['audit_status' => 2, 'next_workprocess_id' => '']);
                $this->create_log($workflow, $content, 'end'); //写入日志--当前操作日志
                $this->create_news($workflow, $workprocess, 'end'); //写入消息--通知发起人流程已完结并且关闭
            } else { //有下一级
                Db::name('wf_workflow')->where('id', $data['workflow_id'])->update(['audit_status' => 1, 'next_workprocess_id' => $workprocess2['id']]); //修改工作流审核进度到下一节点
                //生成后续操作记录
                $this->create_examine($workprocess2);
                $this->create_log($workflow, $content, 'adopt'); //写入日志--当前操作日志
                $this->create_news($workflow, $workprocess2, 'adopt'); //写入消息--通知下一节点的所有审核人
            }
        } elseif ($con_sign == 3) {     //会审--全部通过
            //查询当前节点未审核人数
            $where = array(
                'workflow_id' => $data['workflow_id'],
                'workprocess_id' => $data['next_workprocess_id'],
                'status' => 0
            );
            $list = Db::name('wf_examine')->where($where)->select();
            $ex_where = array(
                'workflow_id' => $workprocess['workflow_id'],
                'workprocess_id' => $workprocess['id'],
                'status' => 0,
                'examine_people'=>$this->now_user,
            );
            if (count($list) == 1) { //说明这是最后一条审核,需要修改工作流表和节点数据表
                //修改对应的操作记录
                Db::name('wf_workprocess')->where(['id' => $data['next_workprocess_id']])->update(['node_status' => 1]);   //先修改当前审批节点状态
                Db::name('wf_examine')->where($ex_where)->update(['status' => 1, 'node_status' => 1]);  //标识操作记录为已经操作
                $workprocess2 = $this->get_some_process($workprocess['id'],'next');  //获取下一节点
                //查询下一节点的节点类型
                $process2 = Db::name('wf_process')->find($workprocess2['process_id']);
                if ($process2['process_type'] == 'is_end') { //没有下一级
                    Db::name('wf_workflow')->where('id', $data['workflow_id'])->update(['audit_status' => 2, 'next_workprocess_id' => '']); //该流程完全通过
                    $this->create_log($workflow, $content, 'end'); //写入日志--当前操作日志
                    $this->create_news($workflow, $workprocess, 'end'); //写入消息--通知发起人流程已完结并且关闭
                } else { //有下一级
                    Db::name('wf_workflow')->where('id', $data['workflow_id'])->update(['audit_status' => 1, 'next_workprocess_id' => $workprocess2['id']]);//修改流程审核进度到下一节点
                    $this->create_examine($workprocess2);//发布下一节点的审核需求到每个审核人
                    $this->create_log($workflow, $content, 'adopt'); //写入日志--当前操作日志
                    $this->create_news($workflow, $workprocess2, 'adopt'); //写入消息--通知下一节点的所有审核人
                }
            } else {  //不需要修改工作流表和节点数据表
                Db::name('wf_examine')->where($ex_where)->update(['status' => 1, 'node_status' => 1]);  //标识操作记录为已经操作
                $this->create_log($workflow, $content, 'adopt'); //写入日志--当前操作日志
            }
        };
        Db::name('wf_workprocess')->where('id','eq',$workprocess2['id'])->update(['source_node'=>$workprocess['id']]);
    }
    /**
     * 创建新的待审核操作信息  workflow_id工作流ID  |  workprocess_id操作节点ID  |  examine_people操作人ID  |  con_sign节点模式  |  audit_status当前被操作节点的状态   / status当前操作状态
     * @param  $param (需要操作的节点信息数组)
     */
    public function create_examine($param)
    {
        $examine_param = array();
        foreach (explode(',', $param['peoples']) as $k => $v) {
            $examine_param[] = array(
                'workflow_id' => $param['workflow_id'],
                'workprocess_id' => $param['id'],
                'examine_people' => $v,
                'con_sign' => $param['con_sign'],
                'node_status' => $param['node_status'],
                'status' => 0,
                'isdelete'=>0,
            );
        };
        Db::name('wf_examine')->insertAll($examine_param);
    }
    /**
     * 创建消息
     * @param $workflow -- 工作流数组
     * @param $workprocess -- 需要发布消息的节点数组
     * @param $type
     */
    public function create_news($workflow, $workprocess, $type)
    {
        $news_param = array();
        $name = Db::name('sys_user')->find($workflow['sponsor'])['username'];
        $flow_name = Db::name('wf_flow')->find($workflow['flow_id'])['name'];
        if ($type == 'repulse') {
            $news_param[] = array(
                'isdelete' => 0,                          //是否删除
                'workflow_id' => $workflow['id'],         //流程ID
                'flow_id' => $workflow['flow_id'],        //流程模版ID
                'workprocess_id' => $workprocess['id'],   //流程节点ID
                'operator' => $this->now_user,        //消息发起人ID
                'notice_people' => $workflow['sponsor'],                    //消息接受人ID
                'is_read' => 0,                           //是否已读
                'content' => '您发起的流程被打回，请修正后重新发起',
            );
        } elseif ($type == 'end') {
            $news_param[] = array(
                'isdelete' => 0,                          //是否删除
                'workflow_id' => $workflow['id'],         //流程ID
                'flow_id' => $workflow['flow_id'],        //流程模版ID
                'workprocess_id' => $workprocess['id'],   //流程节点ID
                'operator' => $this->now_user,        //消息发起人ID
                'notice_people' => $workflow['sponsor'],                    //消息接受人ID
                'is_read' => 0,                           //是否已读
                'content' => '您发起的流程已审核通过，请点击查看',
            );
        } else {
            foreach (explode(',', $workprocess['peoples']) as $k => $v) {
                $msg = "";
                switch ($type) {
                    case 'create':
                        $msg = $name . '发起的' . $flow_name . '流程需要您审批';
                        break;
                    case 'adopt':
                        $msg = $name . '发起的' . $flow_name . '流程需要您审核';
                        break;
                    case 'repeat':
                        $msg = $name . '重新发起的' . $flow_name . '流程需要您审核';
                        break;
                }
                $news_param[] = array(
                    'isdelete' => 0,                          //是否删除
                    'workflow_id' => $workflow['id'],         //流程ID
                    'flow_id' => $workflow['flow_id'],        //流程模版ID
                    'workprocess_id' => $workprocess['id'],   //流程节点ID
                    'operator' => $this->now_user,        //消息发起人ID
                    'notice_people' => $v,                    //消息接受人ID
                    'is_read' => 0,                           //是否已读
                    'content' => $msg
                );
            }
        }
        Db::name('wf_news')->insertAll($news_param);
    }
    /**
     * 流程操作日志
     * @param $data --工作流数组
     * @param $content -- 留言评论
     * @param $type
     */
    public function create_log($data, $content='', $type)
    {
        $log_param = array(
            'isdelete' => 0,                              //是否删除
            'workflow_id' => $data['id'],                 //流程ID
            'flow_id' => $data['flow_id'],                //流程模版ID
            'workprocess_id' => $data['next_workprocess_id'],       //流程节点ID
            'operator' => $this->now_user,    //操作人ID
        );
        $msg = "";
        $flow_name = Db::name('wf_flow')->find($data['flow_id'])['name'];
        $username = session('username');
        switch ($type) {
            case 'create':
                $msg = $username . '发起了' . $flow_name . '审批流';
                $log_param['type'] = 'create';
                $log_param['workprocess_id'] = $data['first_workprocess_id']; //创建的时候是对起始节点操作
                break;
            case 'adopt':
                $log_param['type'] = 'adopt';
                $msg = $username . '审核通过' . $flow_name . '审批流' . $data['next_workprocess_id'] . '节点';
                break;
            case 'repulse':
                $log_param['type'] = 'repulse';
                $msg = $username . '打回了' . $flow_name . '审批流' . $data['next_workprocess_id'] . '节点';
                break;
            case 'end':
                $log_param['type'] = 'end';
                $msg = $username . '结束了' . $flow_name . '审批流';
                break;
            case 'recall':
                $log_param['type'] = 'recall';
                $msg = $username . '撤回了' . $flow_name . '审批流';
                break;
            case 'repeat':
                $log_param['type'] = 'repeat';
                $msg = $username . '重发了' . $flow_name . '审批流';
                break;
        }
        $log_param['msg'] = $msg;
        $log_param['content'] = $content;
        Db::name('wf_log')->insert($log_param);
    }
    /**
     * 获取工作流时间线
     * @param $id --工作流id
     */
    public function get_time_line($id)
    {
        $where = array(
            'l.workflow_id' => $id,
            'l.isdelete' => 0
        );
        //根据日志链操作表进行查询
        $list = Db::name('wf_log')->alias('l')
            ->join('sys_user u', 'l.operator = u.id', 'left')
            ->where($where)
            ->field('l.id as id,l.create_time as time,l.type as type,l.msg as msg,l.content as content,u.name as username')
            ->select();
        return $list;
    }
    /**
     * 表单字段信息查询
     * @param $where ['flow_id'=>value]  流程模版ID条件数组
     * @return bool|false|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_flow_field($where)
    {
        $form_field = Db::name('wf_form_field')->where($where)->select();
        foreach ($form_field as $k => $v) {
            if (!empty($form_field[$k]['content'])) {
                $form_field[$k]['content'] = json_decode($v['content'], true);
            }
        }
        return $form_field;
    }
    /**
     * 审核鉴权方法，用来寻找节点的审核人
     * @param $workflow_id  审批流ID
     * @param $process_id   当前节点ID
     * @param string $type 查询控制 now=当前节点  next=下一节点ID
     *
     */
    public function seek_people($workflow_id, $process_id)
    {
        $seek_people = "";
        $data = Db::name('wf_process')->find($process_id);
        switch ($data['auto_person']) {
            case 1:   //不自动选人
                if ($data['is_head'] == 1) {//判断节点选择了部门主管
                    $dept_arr = Db::name('sys_user')->where(['is_executive'=>1])->wherein('dep_id', $data['range_dept_ids'])->field('id')->select();
                } elseif ($data['is_head'] == 0) {
                    $dept_arr = Db::name('sys_user')->wherein('dep_id', $data['range_dept_ids'])->field('id')->select();
                }
                foreach ($dept_arr as $k => $v) {
                    $dept_arr[$k] = $v['id'];
                }
                //根据角色id去查找对应的人员集合
                $role_arr = Db::name('sys_user')->wherein('roleid', $data['range_role_ids'])->field('id')->select();
                foreach ($role_arr as $k => $v) {
                    $role_arr[$k] = $v['id'];
                }
                $user_arr = explode(',', $data['range_user_ids']);
                $d = array_keys(array_flip($dept_arr) + array_flip($role_arr) + array_flip($user_arr));
                $seek_people = implode(',', $this->filter($d));
                break;
            case 2:   //发起人
                $seek_people = Db::name('wf_workflow')->field('sponsor')->find($workflow_id)['sponsor'];
                break;
            case 3:   //发起人的部门主管
                $sponsor = Db::name('wf_workflow')->field('sponsor')->find($workflow_id)['sponsor'];
                $dept_id = Db::name('sys_user')->where('id', 'eq', $sponsor)->find()['dep_id'];
                $dw = array(
                    'dep_id' => $dept_id,
                    'is_executive' => 1
                );
                $dept_data = Db::name('sys_user')->where($dw)->field('id')->find();
                $seek_people = $dept_data['id'];
                break;
        }
        return $seek_people;
    }
    /**
     * 鉴权规则
     * @param $res
     */
    public function seek_people_config($res)
    {
        $seek_people = "";
        $data = Db::name('wf_process')->find($res['process_id']);
        switch ($data['auto_person']) {
            case 1:   //不自动选人
                if ($data['is_head'] == 1) {//判断节点选择了部门主管
                    $dept_arr = Db::name('sys_user')->where('roleid', 'eq', 3)->wherein('dep_id', $data['range_dept_ids'])->field('id')->select();
                } elseif ($data['is_head'] == 0) {
                    $dept_arr = Db::name('sys_user')->wherein('dep_id', $data['range_dept_ids'])->field('id')->select();
                }
                foreach ($dept_arr as $k => $v) {
                    $dept_arr[$k] = $v['id'];
                }
                //根据角色id去查找对应的人员集合
                $role_arr = Db::name('sys_user')->wherein('roleid', $data['range_role_ids'])->field('id')->select();
                foreach ($role_arr as $k => $v) {
                    $role_arr[$k] = $v['id'];
                }
                $user_arr = explode(',', $data['range_user_ids']);
                $d = array_keys(array_flip($dept_arr) + array_flip($role_arr) + array_flip($user_arr));
                $seek_people = implode(',', $this->filter($d));
                break;
            case 2:   //发起人
                $seek_people = Db::name('wf_workflow')->field('sponsor')->find($res['workflow_id'])['sponsor'];
                break;
            case 3:   //发起人的部门主管
                $sponsor = Db::name('wf_workflow')->field('sponsor')->find($res['workflow_id'])['sponsor'];
                $dept = Db::name('sys_user')->where('id', 'eq', $sponsor)->find()['dep_id'];
                $dw = array(
                    'dep_id' => $dept,
                    'roleid' => '3'   //假设角色3为部门主管
                );
                $dept_data = Db::name('sys_user')->where($dw)->field('id')->find();
                $seek_people = $dept_data['id'];
                break;
        }
        return $seek_people;
    }
    /**
     * 递归节点层级level排序,起始依据为process_type==is_start 排序对比字段为process_to(id包含关系)
     * @param $array
     * @param $level
     * @param $data
     * @return mixed
     */
    public function level_order($array)
    {
        static $level = 0;
        static $data = array();
        if (count($array) > 0) {
            foreach ($array as $k => $v) {
                if ($v['process_type'] == 'is_start') {
                    $v['level'] = $level;
                    $data[$level] = $v;
                    $level++;
                    unset($array[$k]);
                    return $this->level_order($array);
                }else{
                    foreach ($data as $key => $val) {
                        if (in_array($v['process_id'], explode(',', $val['process_to']))) {
                            $v['level'] = $level;
                            $data[$level] = $v;
                            $level++;
                            unset($array[$k]);
                            return $this->level_order($array);
                        }
                    }
                }
            }
        } else {
            return $data;
        }
        return $data;
    }
    /**
     * 正则去除开头和结尾的单引号
     * @param $str
     * @return int
     */
    function remove_quote(&$str)
    {
        if (preg_match("/^\'/", $str)) {
            $str = substr($str, 1, strlen($str) - 1);
        }
        //判断字符串是否以'''结束
        if (preg_match("/\'$/", $str)) {
            $str = substr($str, 0, strlen($str) - 1);;
        }
        $str = intval($str);
        return $str;
    }
    /**
     * 匹配返回符合的数组元素
     * @param $str     匹配规则
     * @param $array   操作数组
     * @param $rely    匹配凭借  key|value
     * @param $type    是否清除key中多余字符串
     */
    public function match_element($str, $array, $rely, $type = false)
    {
        $data = array();
        foreach ($array as $k => $v) {
            if ($v != '') {
                if ($rely == 'key') {
                    if (strpos($k, $str) !== false) {
                        if ($type == false) {
                            $data[$k] = $v;
                        } elseif ($type == true) {
                            $data[str_replace($str, '', $k)] = $v;
                        }
                    }
                } elseif ($rely == 'value') {
                    if (strpos($v, $str) !== false) {
                        if ($type == false) {
                            $data[$k] = $v;
                        } elseif ($type == true) {
                            $data[$k] = str_replace($str, '', $v);
                        }
                    }
                }
            }
        }
        return $data;
    }
    /**
     *增加xmselect的选择记忆项
     * @param $id     节点ID
     * @param $array  待处理数组
     * @param $str    对比字段
     */
    public function default_select($id, $array, $str)
    {
        $basic = Db::name('wf_process')->field($str)->find($id);
        foreach ($basic as $k => $v) {
            $basic[$k] = explode(',', $v);
        }
        foreach ($array as $k => $v) {
            if (in_array($v['value'], $basic[$str])) {
                $array[$k]['selected'] = true;
            }
        }
        return $array;
    }
    /**
     * * 根据数组条件修改json中，键的对应值
     * $arr1  条件数组
     * json   需替换的字段
     */
    public function handle_json($arr, $json)
    {
        $array = json_decode($json, true);  //转换为数组
        foreach ($arr as $k => $v) {
            if (isset($array[$k])) {
                $array[$k] = $v;
            }
        }
        return json_encode($array);
    }
    /**
     * 据说适用于10W高并发场景得对象转数组方法
     * @param $object
     * @return mixed
     */
    public function object2array(&$object)
    {
        $object = json_decode(json_encode($object), true);
        return $object;
    }
    /**
     * 过滤空元素
     */
    public function filter($array)
    {
        foreach ($array as $k => $v) {
            $v = trim($v);
            if (empty($v)) {
                if($v!=='0'){
                    unset($array[$k]);
                }
            }
        }
        return $array;
    }
    /**
     * layui分片上传   概念性方法，暂不可用
     */
    public function layui_part_upload()
    {
        $status = 1;
        //上传文件要保存的路径
        $fname = sprintf('/tmp/%s.%s', $_POST['fileName'], $_POST['fileExt']);
        $data = file_get_contents($_FILES['file']['tmp_name']);
        if ($_POST['page'] == 1) {
            file_put_contents($fname, $data);
        } else {
            //其余文件追加到文件末尾
            file_put_contents($fname, $data, FILE_APPEND);
        }
        //最后一片文件
        if ($_POST['totalPage'] == $_POST['page']) {
            $status = 2;
        }
        //返回上传状态
        $res = ['status' => $status, 'downUrl' => "http://localhost/data.dat"];
        echo json_encode($res);
    }
    /**
     * 获取附件列表
     * @param $workflow_id
     * @return bool|false|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_down_list($workflow_id){
        $file_ids = explode(',',Db::name('wf_workflow')->field('file_ids')->find($workflow_id)['file_ids']);
        //获取附件列表
        $list  = Db::name('wf_files')->alias('f')
            ->join('sys_user u','u.id = f.user_id','left')
            ->field('f.id as id,f.name as name,f.new_name as new_name,f.format as format,f.folder as folder,f.complete_path as complete_path,u.username as username')
            ->where(['f.isdelete'=>0])
            ->whereIn('f.id',$file_ids)
            ->select();
        return $list;
    }
    /**
     * layui 整体上传
     */
    public function layui_upload()
    {
        $file = request()->file('file'); // 获取上传的文件
        if ($file == null) {
            exit(json_encode(array('code' => 1, 'msg' => '未上传文件')));
        }
        // 获取文件后缀
        $temp = explode(".", $_FILES["file"]["name"]);          //原文件名|文件类型
        $extension = end($temp);
        $path = ROOT_PATH . 'public' . '/' . 'upload'.'/'.'tmp';                  //D:\phpstudy_pro\WWW\OA_object\public\upload\tmp
        $info = $file->move($path);                                            // 移动文件到指定目录 没有则创建
        $fname = $info->getSaveName();
        $temps=explode('/', $fname);
        $folder = array_shift($temps);                               //获取时间文件夹
        $new_name = explode(".", end($temps))[0];           //新的文件名
        $complete_path = $path.'/'.$fname;                                 //本地完整路径
        $relative_path = 'public/upload/tmp/' . $folder.'/'.$temps[0];               //相对地址  --以后会有用？直觉？
        $param = array(
            'user_id'=>$this->now_user,  //归属人
            'name'=>$temp[0],  //原文件名
            'format'=>$temp[1], //文件格式
            'folder'=>$folder,   //所在本地文件夹
            'new_name'=>$new_name, //系统内分配的文件名
            'complete_path'=>$relative_path, //相对路径
        );
        //信息存入数据库返回ID进行绑定
        Db::name('wf_files')->insert($param);
        $file_id = Db::name('wf_files')->getLastInsID();
        $param['file_id'] = $file_id;
        return $this->success('成功','', $param);
    }
    /**
     * 下载
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function download()
    {
            $id = input('id');
            $url = Db::name('wf_files')->find($id);
            $complete_path = ROOT_PATH.$url['complete_path'];
            // 检查文件是否存在
            if (!file_exists($complete_path)){
                $this->error('文件未找到');
            }else{
                // 打开文件
                $file1 = fopen($complete_path, "r");
                // 输入文件标签
                Header("Content-type: application/octet-stream");
                Header("Accept-Ranges: bytes");
                Header("Accept-Length:".filesize($complete_path));
                header('Content-Disposition: attachment; filename=' . $url['name'].'.'.$url['format']);
                header('Content-Type: application/octet-stream; name=' . $url['name'].'.'.$url['format']);
                ob_clean();     // 重点！！！可以清除文件中多余的路径名以及解决乱码的问题
                flush();        // 重点！！！！：
                //输出文件内容
                //读取文件内容并直接输出到浏览器
                $content = fread($file1, filesize($complete_path));
                echo $content;
                exit();
            }
    }
    /*******************************内部调用增删改的方法接口*****************************/
    /**
     * auto创建工作流
     * @param $id  创建工作流参数  --关联数据ID
     * @param $controller  创建工作流参数  --控制器名
     * @param string $array  提交新建流程的原始数据，没有就不传
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function create_workflow($id,$controller,$array=''){
        $flow = Db::name('wf_flow')->where(['controller'=>$controller])->find();
        $param = array(
            'form_extend'=>$id,
            'flow_id'=>$flow['id'],
            'sponsor' => $this->now_user,       //发起人
            'isdelete' => 0,                    //是否删除
            'audit_status' => 1,                //流程审批状态
        );
        //写入流程表
        Db::name('wf_workflow')->insert($param);
        $workflow_id = Db::name('wf_workflow')->getLastInsID();
        /*******************分配审批流数据节点(初始化)*********************/
        $process = Db::name('wf_process')->where('flow_id', 'eq', $param['flow_id'])->select();  //查询模版节点信息
        $workprocess_param = array();
        foreach ($process as $k => $v) {
            $workprocess_param[$k]['workflow_id'] = $workflow_id;            //工作流ID
            $workprocess_param[$k]['process_id'] = $v['id'];                 //模版节点ID
            $workprocess_param[$k]['con_sign'] = $v['con_sign'];             //节点审批模式
            if ($v['process_type'] == 'is_start') {
                $workprocess_param[$k]['node_status'] = 1;                   //节点审核状态
            } else {
                $workprocess_param[$k]['node_status'] = 0;
            }
            $workprocess_param[$k]['is_delegate'] = 0;                       //是否进行了委派
            $workprocess_param[$k]['legate_users'] = '';                     //委派人员/人员集
            $workprocess_param[$k]['legate_roles'] = '';                     //委派角色/角色集
            $workprocess_param[$k]['legate_depts'] = '';                     //委派部门/部门集
            $workprocess_param[$k]['isdelete'] = 0;
        }
        Db::name('wf_workprocess')->insertAll($workprocess_param);  //入库
        /***************************循环插入审核人id**************************/
        foreach ($process as $k => $v) {
            $where = array(
                'workflow_id' => $workflow_id,
                'process_id' => $v['id'],
            );
            if($v['process_type'] == 'is_start' || $v['process_type'] =='is_end' ){
                $peoples = null;
            }else{
                $peoples = $this->seek_people($workflow_id, $v['id']); //查找审核人
                Db::name('wf_workprocess')->where($where)->update(['peoples' => (int)$peoples]);
            }
        }
        /*******************获取起始流程节点信息和下一步流程节点信息*****************/
        $first_workprocess = $this->get_some_process($workflow_id,'first');  //获取起始节点信息 一维数组
        $workprocess = $this->get_some_process($first_workprocess['id'],'next');  //获取下一节点
        /****************回写起始节点和下一节点id到流程表以及下一节点的来源ID*****************/
        Db::name('wf_workflow')->where('id', 'eq', $workflow_id)->update(['first_workprocess_id' => $first_workprocess['id'], 'next_workprocess_id' => $workprocess['id']]);
        Db::name('wf_workprocess')->where('id','eq',$workprocess['id'])->update(['source_node'=>$first_workprocess['id']]);
        /*********************流程信息查询*******************/
        $workflow = Db::name('wf_workflow')->find($workflow_id);
        /*********************写入消息表***********************/
        $this->create_news($workflow, $workprocess, 'create');
        /*********************写入审核操作表*********************/
        $this->create_examine($workprocess);
        /*********************写入日志表*************************/
        $content = isset($array['content'])?$array['content']:'';
        $this->create_log($workflow, $content, 'create');
        return $workflow_id;
    }
    /**
     * auto重新发起表单
     * @param $workflow  即时查询的需要修改的流程
     * @param $input  修改的原始数据，可以为空
     * @return bool
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function repeat_work_flow($id,$controller,$input=''){
        $flow_id = Db::name('wf_flow')->where(['controller'=>$controller])->find()['id'];
        $params = array(
            'form_extend'=>$id,
            'flow_id'=>$flow_id,
        );
        $workflow = Db::name('wf_workflow')->where($params)->find();
        $param['audit_status'] = 1;
        //修改初始节点状态
        Db::name('wf_workprocess')->where(['id'=>$workflow['first_workprocess_id']])->update(['node_status'=>1]);
        //修改流程表
        Db::name('wf_workflow')->where(['id'=>$workflow['id']])->update($param);
        //根据新数据重新验证下一节点的选择
        $workprocess = $this->get_some_process($workflow['first_workprocess_id'],'next');
        //修改初始节点状态
        Db::name('wf_workprocess')->where(['id'=>$workflow['first_workprocess_id']])->update(['node_status'=>1]);
        //回写下一审核节点
        Db::name('wf_workflow')->where(['id'=>$workflow['id']])->update(['next_workprocess_id'=>$workprocess['id']]);
        /****************************流程信息查询*************************/
        $workflows = Db::name('wf_workflow')->find($workflow['id']);
        /*********************写入消息表***********************/
        $this->create_news($workflows, $workprocess, 'create');
        /*********************写入审核操作表*********************/
        $this->create_examine($workprocess);
        /*********************写入日志表*************************/
        $content = isset($input['content'])?$input['content']:'';
        $this->create_log($workflows, $content, 'repeat');
        if($workflows['audit_status']==1){
            return true;
        }else{
            return false;
        };
    }
    /**
    * 流程删除方法
    */
    public function auto_delect_workflow($id,$controller){
        $flow_id = Db::name('ht_formtype')->where(['controller'=>$controller])->find()['flow_id'];
        $param = array(
            'form_extend'=>$id,
            'flow_id'=>$flow_id,
        );
        $workflow = Db::name('wf_workflow')->where($param)->find();
        $bool = $this->deleteaction($workflow['id']);
        return $bool;
    }
    /**
     * 删除流程方法
     * @param $workflow_id  需要流程ID
     * @return bool
     */
    public function deleteaction($workflow_id){
        try {
            //删除对应操作表
            Db::name('wf_examine')->where('workflow_id', 'eq', $workflow_id)->update(['isdelete' => 1]);
            //删除相关节点数据
            Db::name('wf_workprocess')->where('workflow_id', 'eq', $workflow_id)->update(['isdelete' => 1]);
            //删除审批流模版
            Db::name('wf_workflow')->where('id', 'eq', $workflow_id)->update(['isdelete' => 1]);
            Db::commit();
            $bool = true;
        } catch (\Exception $e) {
            Db::rollback();
            $bool = false;
        }
        return $bool;
    }
    /*******************************************list列表*****************************************/
    /**
     * 各个报表列表页获取数据的方法
     */
    public function get_list(){
        if(request()->isAjax()){
            $params = request()->param();
            $type = $params['type'];
            $controller = '当前控制器';
            $param =array();
            if(isset($params['page'])  && $params['page']!= ''){
                $page = $params['page'];
            }
            if(isset($params['limit'])  && $params['limit']!= ''){
                $limit = $params['limit'];
            }
            if(isset($params['id'])  && $params['id']!= ''){
                $param['wo.id'] = $params['id'];
            }
            if(isset($params['name']) && $params['name']!= ''){
                $param['fl.name'] = ['like',"%".$params['name']."%"];
            }
            $data = array();
            $mdeol = new Workflowajax();
            $data = $mdeol->get_list_data($param,$page,$limit,$type,$controller);
            return $data;
        }
    }
    /**
     * 获取列表数据
     * @param $param         其他参数
     * @param $page          页数
     * @param $limit         每页数量
     * @param $type         当前状态（1-流程列表，2-审批列表）
     * @param $controller   当前控制器名
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_list_data($param,$page,$limit,$type,$controller){
        $workflwo = new Workflowajax();
        $param['wo.isdelete']=0;
        if($type==1){
            $param['wo.sponsor']=session('id');
            $data = $workflwo->get_workflow_lists($controller,$param,$page,$limit);
        }elseif($type = 2){
            $data = $workflwo->get_check_list($controller,$param,$page,$limit);
        }
        if($data){
            $ret['data'] = $data;
            $ret['code'] = 0;
            $ret['msg']  = '获取数据成功';
        }else{
            $ret['data'] = '';
            $ret['code'] = -1;
            $ret['msg']  = '获取数据为空';
        }
        return $data;
    }
    /**
     * 获取列表方法
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function get_workflow_lists($controller,$param,$page,$limit){
        $param['fl.controller']=$controller;
        $list = Db::name('wf_workflow')->alias('wo')
            ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left')
            ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left')
            ->join('wf_process p','wp.process_id = p.id','left')
            ->join('sys_user u','u.id=wo.sponsor','left')
            ->field('fl.controller,wo.id as id,fl.name as name,wo.flow_id as flow_id,u.name as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend')
            ->where($param)
            ->order('wo.id','asd')
            ->paginate($limit,false,['page'=>$page]);
        $list = $list->toArray();
        //循环替换审核人名
        foreach($list['data'] as $key=>$val){
            $peoples = Db::name('sys_user')->whereIn('id',explode(',',$val['peoples']))->field('name')->select();
            foreach($peoples as $k=>$v){
                $peoples[$k] = $v['name'];
            }
            $list['data'][$key]['peoples'] = implode(',',$peoples);
        }
        $data = array(
            'code' => '200',
            'msg' => '请求成功',
            'count' => $list['total'],
            'data' => $list['data'],
        );
        return $data;
    }
    /**
     *获取待审核列表
     */
    public function get_check_list($controller,$param,$page,$limit){
        $where['isdelete'] =0;
        $roleid = session('roleid');
        if( $param['state']!= 2){
            $where['examine_people'] = $this->now_user;
        }
        if(isset($param['state'])){
            if($param['state']==0){
                $where['status'] = 0; //待审核
            }elseif($param['state']==1){
                $where['status'] = 1;
            }
        }
        //去重查询出所有待审核操作涉及的流程ID
        $examineall = Db::name('wf_examine')->where($where)->distinct(true)->field('workflow_id')->order('workflow_id desc')->select();
        foreach ($examineall as $k => $v) {
            $examineall[$k] = $v['workflow_id'];
        }
        if(!empty($controller)){
            $param['fl.controller']=$controller;
        }
        unset($param['state']);
        //查询相关流程
        $list = Db::name('wf_workflow')->alias('wo')
            ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left')
            ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left')
            ->join('wf_process p','wp.process_id = p.id','left')
            ->join('sys_user u','u.id=wo.sponsor','left')
            ->field('fl.controller,wo.id as id,fl.name as name,wo.flow_id as flow_id,u.name as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend')
            ->where($param)
            ->whereIn('wo.id', $examineall)  //根据符合的流程id查询
            ->order('wo.id','asd')
            ->paginate($limit,false,['page'=>$page]);
        $list = $list->toArray();
        //循环替换审核人名
        foreach($list['data'] as $key=>$val){
            $peoples = Db::name('sys_user')->whereIn('id',explode(',',$val['peoples']))->field('name')->select();
            if(!in_array($this->now_user,explode(',',$val['peoples']))){
                $list['data'][$key]['is_qualifications'] = 1;
            }else{
                $list['data'][$key]['is_qualifications'] = 0;
            }
            foreach($peoples as $k=>$v){
                $peoples[$k] = $v['name'];
            }
            $list['data'][$key]['peoples'] = implode(',',$peoples);
        }
        foreach ($list['data'] as $key => $val) {
            $list['data'][$key]['index'] = $val['controller'].'/details';
        }
        $data = array(
            'code' => '200',
            'msg' => '请求成功',
            'count' => $list['total'],
            'data' => $list['data'],
        );
        return $data;
    }
    /***************************************************************************************/
}